import hashlib
import math
import os
import queue
import threading
import time
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext

import crcmod
import serial
import serial.tools.list_ports
import ttkbootstrap as ttkb
from ttkbootstrap.constants import *

from app.util.annotation_util import ClassInfo, annotate
from app.view.base_view import View


@annotate(ClassInfo(name="DFU Serial", category="ft_tool"))
class FtSerialUpdateView(View):
    """设置视图"""

    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # 串口相关变量
        self.serial_port = None
        self.is_connected = False
        self.ports = []
        self.baud_rates = [9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600]

        # 固件相关变量
        self.firmware_path = ""
        self.firmware_data = b""
        self.firmware_md5 = ""
        self.provided_md5 = ""

        # 升级状态变量
        self.upgrade_in_progress = False
        self.Upgrade_success = False
        self.packet_size = 1024 * 5  # 分包大小2K
        self.total_packets = 0
        self.current_packet = 0

        # 消息队列用于线程间通信
        self.msg_queue = queue.Queue()
        self.receive_queue = queue.Queue()

        # 创建UI
        self._create_widgets()

        # 启动消息处理线程
        self.start_message_thread()

        # 初始搜索串口
        self.search_ports()

        # ToDo 加载默认固件 打开串口
        #self.load_default_firmware()
        #self.toggle_connection()

    def _create_widgets(self):
        # 创建主框架
        main_frame = ttkb.Frame(self, padding=10)
        main_frame.pack(fill=BOTH, expand=True)

        # 顶部控制区域
        control_frame = ttkb.LabelFrame(main_frame, text="控制中心", padding=10)
        control_frame.pack(fill=X, pady=(0, 10))

        # 串口设置区域
        port_frame = ttkb.Frame(control_frame)
        port_frame.pack(fill=X, pady=(0, 10))

        ttkb.Label(port_frame, text="串口:").grid(row=0, column=0, padx=5, pady=5, sticky=W)
        self.port_var = tk.StringVar()
        self.port_combobox = ttkb.Combobox(
            port_frame,
            textvariable=self.port_var,
            state="readonly",
            width=15
        )
        self.port_combobox.grid(row=0, column=1, padx=5, pady=5)

        ttkb.Label(port_frame, text="波特率:").grid(row=0, column=2, padx=5, pady=5, sticky=W)
        self.baud_var = tk.IntVar(value=921600)
        self.baud_combobox = ttkb.Combobox(
            port_frame,
            textvariable=self.baud_var,
            values=self.baud_rates,
            state="readonly",
            width=10
        )
        self.baud_combobox.grid(row=0, column=3, padx=5, pady=5)

        ttkb.Button(port_frame, text="搜索串口", command=self.search_ports, bootstyle=OUTLINE).grid(
            row=0, column=4, padx=5, pady=5)
        self.connect_btn = ttkb.Button(
            port_frame,
            text="打开串口",
            command=self.toggle_connection,
            bootstyle=SUCCESS
        )
        self.connect_btn.grid(row=0, column=5, padx=5, pady=5)
        self.log_clear_btn = ttkb.Button(
            port_frame,
            text="清除LOG",
            command=self.log_clear,
            bootstyle=SUCCESS
        )
        self.log_clear_btn.grid(row=0, column=6, padx=5, pady=5)
        # 固件设置区域
        firmware_frame = ttkb.Frame(control_frame)
        firmware_frame.pack(fill=X, pady=(0, 10))

        ttkb.Label(firmware_frame, text="固件文件:").grid(row=0, column=0, padx=5, pady=5, sticky=W)
        self.firmware_path_var = tk.StringVar(value="未选择文件")
        ttkb.Label(firmware_frame, textvariable=self.firmware_path_var).grid(
            row=0, column=1, padx=5, pady=5, sticky=W)
        ttkb.Button(firmware_frame, text="加载固件", command=self.load_firmware, bootstyle=OUTLINE).grid(
            row=0, column=2, padx=5, pady=5)

        # MD5校验区域
        md5_frame = ttkb.Frame(control_frame)
        md5_frame.pack(fill=X, pady=(0, 10))

        ttkb.Label(md5_frame, text="固件MD5:").grid(row=0, column=0, padx=5, pady=5, sticky=W)
        self.firmware_md5_var = tk.StringVar(value="")
        ttkb.Label(md5_frame, textvariable=self.firmware_md5_var).grid(
            row=0, column=1, padx=5, pady=5, sticky=W)

        ttkb.Label(md5_frame, text="目标MD5:").grid(row=0, column=2, padx=5, pady=5, sticky=W)
        self.target_md5_var = tk.StringVar(value="")
        ttkb.Entry(md5_frame, textvariable=self.target_md5_var, width=32).grid(
            row=0, column=3, padx=5, pady=5, sticky=W)

        self.md5_check_btn = ttkb.Button(
            md5_frame,
            text="校验MD5",
            command=self.check_md5,
            bootstyle=OUTLINE,
            state=DISABLED
        )
        self.md5_check_btn.grid(row=0, column=4, padx=5, pady=5)

        self.info_sent_btn = ttkb.Button(
            md5_frame,
            text="发送INFO",
            command=self.sent_info,
            bootstyle=OUTLINE,
        )
        self.info_sent_btn.grid(row=0, column=5, padx=5, pady=5)

        self.data_sent_btn = ttkb.Button(
            md5_frame,
            text="发送数据",
            command=self.sent_data_transfer,
            bootstyle=OUTLINE,
        )
        self.data_sent_btn.grid(row=0, column=6, padx=5, pady=5)

        ttkb.Label(md5_frame, text="起始地址:").grid(row=1, column=0, padx=5, pady=5, sticky=W)
        self.hex_dump_start_addr_var = tk.StringVar(value="0x08002000")
        ttkb.Entry(md5_frame, textvariable=self.hex_dump_start_addr_var, width=32).grid(
            row=1, column=1, padx=5, pady=5, sticky=W)
        ttkb.Label(md5_frame, text="读取长度:").grid(row=1, column=2, padx=5, pady=5, sticky=W)
        self.hex_dump_len_var = tk.StringVar(value="512")
        ttkb.Entry(md5_frame, textvariable=self.hex_dump_len_var, width=32).grid(
            row=1, column=3, padx=5, pady=5, sticky=W)
        self.hex_dump_btn = ttkb.Button(
            md5_frame,
            text="HexDump",
            command=self.sent_hex_dump,
            bootstyle=OUTLINE,
        )
        self.hex_dump_btn.grid(row=1, column=4, padx=5, pady=5)

        self.firmware_sent_btn = ttkb.Button(
            md5_frame,
            text="发送固件",
            command=self.firmware_sent,
            bootstyle=OUTLINE,
        )
        self.firmware_sent_btn.grid(row=1, column=5, padx=5, pady=5)

        # 升级控制区域
        upgrade_frame = ttkb.Frame(control_frame)
        upgrade_frame.pack(fill=X)

        self.upgrade_btn = ttkb.Button(
            upgrade_frame,
            text="开始升级",
            command=self.start_upgrade,
            bootstyle=PRIMARY,
            state=DISABLED
        )
        self.upgrade_btn.pack(side=LEFT, padx=5, pady=5)

        self.cancel_btn = ttkb.Button(
            upgrade_frame,
            text="取消升级",
            command=self.cancel_upgrade,
            bootstyle=DANGER,
            state=DISABLED
        )
        self.cancel_btn.pack(side=LEFT, padx=5, pady=5)

        # 进度条
        self.progress_var = tk.DoubleVar(value=0)
        self.progress_bar = ttkb.Progressbar(
            upgrade_frame,
            variable=self.progress_var,
            length=300,
            mode="determinate"
        )
        self.progress_bar.pack(side=LEFT, padx=5, pady=5, fill=X, expand=True)

        # 日志区域
        log_frame = ttkb.LabelFrame(main_frame, text="升级日志", padding=10)
        log_frame.pack(fill=BOTH, expand=True)

        self.log_text = scrolledtext.ScrolledText(
            log_frame,
            wrap=tk.WORD,
            font=("Consolas", 10),
            state=tk.DISABLED
        )
        self.log_text.pack(fill=BOTH, expand=True)

        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        self.status_bar = ttkb.Label(self, textvariable=self.status_var, anchor=W)
        self.status_bar.pack(side=BOTTOM, fill=X)

    def log_clear(self):
        self.log_text.config(state=tk.NORMAL)
        self.log_text.delete('1.0', tk.END)
        self.log_text.see(tk.END)
        self.log_text.config(state=tk.DISABLED)

    def start_message_thread(self):
        """启动消息处理线程"""
        self.running = True
        threading.Thread(target=self.process_messages, daemon=True).start()

    def process_messages(self):
        """处理消息队列中的消息"""
        while self.running:
            try:
                msg = self.msg_queue.get(timeout=0.05)
                self.log(msg)
                self.msg_queue.task_done()
            except queue.Empty:
                continue

    def log(self, message):
        """在日志区域添加消息"""
        self.log_text.config(state=tk.NORMAL)
        timestamp = time.strftime("%H:%M:%S")
        self.log_text.insert(tk.END, f"[{timestamp}] {message}\n")
        self.log_text.see(tk.END)
        self.log_text.config(state=tk.DISABLED)

    def search_ports(self):
        """搜索可用串口"""
        self.log("正在搜索串口...")
        self.ports = []
        ports = serial.tools.list_ports.comports()
        for port in ports:
            self.ports.append(port.device)

        self.port_combobox['values'] = self.ports
        if self.ports:
            self.port_combobox.current(len(self.port_combobox['values']) - 1)
            self.log(f"找到 {len(self.ports)} 个串口")
        else:
            self.log("未找到可用串口")

    def toggle_connection(self):
        """切换串口连接状态"""
        if self.is_connected:
            self.close_port()
        else:
            self.open_port()

    def open_port(self):
        """打开串口"""
        try:
            port = self.port_var.get()
            baud = self.baud_var.get()

            if not port:
                messagebox.showerror("错误", "请选择串口")
                return

            self.serial_port = serial.Serial(
                port=port,
                baudrate=baud,
                timeout=1,
                write_timeout=1
            )

            if self.serial_port.is_open:
                self.is_connected = True
                self.connect_btn.config(text="关闭串口", bootstyle=DANGER)
                self.log(f"已打开串口 {port}，波特率 {baud}")

                # 启动串口监听线程
                threading.Thread(target=self.read_serial, daemon=True).start()

                # 启用升级按钮（如果已加载固件）
                if self.firmware_path:
                    self.upgrade_btn.config(state=NORMAL)
        except Exception as e:
            self.log(f"打开串口失败: {str(e)}")
            messagebox.showerror("错误", f"打开串口失败: {str(e)}")

    def close_port(self):
        """关闭串口"""
        try:
            if self.serial_port and self.serial_port.is_open:
                self.serial_port.close()

            self.is_connected = False
            self.connect_btn.config(text="打开串口", bootstyle=SUCCESS)
            self.log("串口已关闭")

            # 禁用升级按钮
            self.upgrade_btn.config(state=DISABLED)
        except Exception as e:
            self.log(f"关闭串口失败: {str(e)}")

    def read_serial(self):
        """读取串口数据的线程函数"""
        while self.is_connected and self.serial_port.is_open:
            try:
                if self.serial_port.in_waiting > 0:
                    data = self.serial_port.read_all()
                    try:
                        text = data.decode('utf-8', errors='replace')
                        self.receive_queue.put(data)
                        # self.msg_queue.put(f"data: {data.hex()}")
                        self.msg_queue.put(f"设备: {text.strip()}")
                    except:
                        self.msg_queue.put(f"设备接收二进制数据: {len(data)} 字节")

                time.sleep(0.01)
            except Exception as e:
                if self.is_connected:  # 只有在连接状态下的错误才报告
                    self.msg_queue.put(f"串口读取错误: {str(e)}")
                break

    def send_command(self, command):
        """发送命令到串口"""
        if not self.is_connected or not self.serial_port or not self.serial_port.is_open:
            return False
        try:
            self.serial_port.write(command)
            self.log(f"已发送发送命令")
            return True
        except Exception as e:
            self.log(f"发送命令失败: {str(e)}")
            return False

    def sent_data_transfer(self):
        type_info = 0x0F
        block_size = b"\x00\x00\x00\x12"
        total_blocks = b"\x00\x00\x00\x12"
        current_block = b"\x00\x00\x00\x12"
        firmware_data = b"\x00\x00\x00\x12"
        self.firmware_data_transfer(
            block_size=block_size,
            total_blocks=total_blocks,
            current_block=current_block,
            firmware_data=firmware_data
        )

    def sent_hex_dump(self):
        type_info = 0x00000014
        addr = int(self.hex_dump_start_addr_var.get().strip(), 16).to_bytes(4, byteorder="big")
        length = int(self.hex_dump_len_var.get().strip()).to_bytes(4, byteorder="big")
        data = addr + length
        command = self.construct_command(type_info, data)
        self.send_command(command)

    def firmware_sent(self):
        type_info = 0x00000015
        start_addr_dec = int(self.hex_dump_start_addr_var.get().strip(), 16)
        batch_len_dec = int(self.hex_dump_len_var.get().strip())
        batch_len_bytes = int(batch_len_dec).to_bytes(4, byteorder="big")
        firmware_data = self.firmware_data

        batch_total = math.ceil(len(firmware_data) / batch_len_dec)
        # 分批发送数据
        for counter in range(batch_total):
            batch_data = firmware_data[(counter * batch_len_dec):((counter + 1) * batch_len_dec)]
            print(f"Batch:{counter}")
            index = 0
            for cur_data in batch_data:
                index += 1
                print(int(cur_data).to_bytes(1, byteorder="big").hex().upper(), end=" ")
                if index % 16 == 0:
                    print("\r\n")
            start_addr_bytes = int(start_addr_dec).to_bytes(4, byteorder="big")
            data = start_addr_bytes + batch_len_bytes + batch_data
            command = self.construct_command(type_info, data)
            self.send_command(command)
            time.sleep(0.5)
            # 更改写入地址
            start_addr_dec += batch_len_dec

    def firmware_data_transfer(self, block_size, total_blocks, current_block, current_block_size, firmware_data):
        type_info = 0x0F
        data = block_size + total_blocks + current_block + current_block_size + firmware_data
        # print(len(data))
        command = self.construct_command(type_info, data)
        self.send_command(command)

    def sent_reset(self):
        type_info = 0x0E
        command = self.construct_command(type_info, b"")
        self.send_command(command)

    def sent_info(self):
        type_info = 0x12

        author = b"\x4C\x61\x74\x65\x66\x6C\x79\x00\x00\x00\x00\x12\x00\x00\x00\x00"
        compile_time = b"\x00\x00\x00\x12\x00\x00\x00\x12"
        sw_version = b"\x00\x00\x00\x12"
        hw_version = b"\x00\x00\x00\x12"
        hw_code = b"\x4C\x61\x74\x65\x66\x6C\x79\x00\x00\x00\x00\x12\x00\x00\x00\x00"
        device_type = b"\x00\x00\x00\x12"
        magic_header = b"\x1A\x7E\xF1\x40"
        fw_addr = b"\x00\x00\x00\x12"
        fw_size = b"\x00\x00\x00\x12"
        block_size = b"\x00\x00\x00\x12"
        total_blocks = b"\x00\x00\x00\x12"
        data = author + compile_time + sw_version + hw_version + hw_code + device_type + magic_header + fw_addr + fw_size + block_size + total_blocks
        print(len(data))
        command = self.construct_command(type_info, data)
        self.send_command(command)

    def load_default_firmware(self):
        """加载固件文件"""
        file_path = "C:\\Users\\latefly\\Desktop\\IotSolution\\2-Embed\\MicroBootloader\\stm32f103c8\\App\OBJ\\App.bin"
        if file_path:
            try:
                with open(file_path, "rb") as f:
                    self.firmware_data = f.read()

                self.firmware_path = file_path
                self.firmware_path_var.set(os.path.basename(file_path))

                # 计算固件MD5
                md5_hash = hashlib.md5()
                md5_hash.update(self.firmware_data)
                self.firmware_md5 = md5_hash.hexdigest()
                self.firmware_md5_var.set(self.firmware_md5)
                # ToDo 暂时自动填充
                self.target_md5_var.set(self.firmware_md5)

                self.log(f"已加载固件: {os.path.basename(file_path)}, 大小: {len(self.firmware_data)} 字节")

                # 启用MD5校验按钮
                self.md5_check_btn.config(state=NORMAL)

                # 如果串口已打开，启用升级按钮
                if self.is_connected:
                    self.upgrade_btn.config(state=NORMAL)
                counter = 0
                for cur_data in self.firmware_data:
                    counter += 1
                    print(int(cur_data).to_bytes(1, byteorder="big").hex().upper(), end=" ")
                    if (counter % 16) == 0:
                        print("\r\n")

            except Exception as e:
                self.log(f"加载固件失败: {str(e)}")
                messagebox.showerror("错误", f"加载固件失败: {str(e)}")

    def load_firmware(self):
        """加载固件文件"""
        file_path = filedialog.askopenfilename(
            title="选择固件文件",
            filetypes=[("固件文件", "*.bin;*.hex;*.firmware"), ("所有文件", "*.*")]
        )

        if file_path:
            try:
                with open(file_path, "rb") as f:
                    self.firmware_data = f.read()

                self.firmware_path = file_path
                self.firmware_path_var.set(os.path.basename(file_path))

                # 计算固件MD5
                md5_hash = hashlib.md5()
                md5_hash.update(self.firmware_data)
                self.firmware_md5 = md5_hash.hexdigest()
                self.firmware_md5_var.set(self.firmware_md5)
                # ToDo 暂时自动填充
                self.target_md5_var.set(self.firmware_md5)

                self.log(f"已加载固件: {os.path.basename(file_path)}, 大小: {len(self.firmware_data)} 字节")

                # 启用MD5校验按钮
                self.md5_check_btn.config(state=NORMAL)

                # 如果串口已打开，启用升级按钮
                if self.is_connected:
                    self.upgrade_btn.config(state=NORMAL)
            except Exception as e:
                self.log(f"加载固件失败: {str(e)}")
                messagebox.showerror("错误", f"加载固件失败: {str(e)}")

    def check_md5(self):
        """校验固件MD5"""
        self.provided_md5 = self.target_md5_var.get().strip().lower()

        if not self.firmware_path:
            messagebox.showwarning("警告", "请先加载固件")
            return

        if not self.provided_md5:
            messagebox.showwarning("警告", "请输入目标MD5")
            return

        if self.firmware_md5 == self.provided_md5:
            self.log("MD5校验成功，固件匹配")
            # messagebox.showinfo("成功", "MD5校验成功，固件匹配")
            return True
        else:
            self.log(f"MD5校验失败，固件MD5: {self.firmware_md5}, 目标MD5: {self.provided_md5}")
            messagebox.showerror("失败", "MD5校验失败，固件不匹配")
            return False

    def start_upgrade(self):
        """开始固件升级流程"""
        # 检查固件是否已加载
        if not self.firmware_path:
            messagebox.showwarning("警告", "请先加载固件")
            return

        # 检查MD5（如果已提供）
        self.provided_md5 = self.target_md5_var.get().strip().lower()
        if self.provided_md5 and not self.check_md5():
            return

        # 检查串口连接
        if not self.is_connected or not self.serial_port or not self.serial_port.is_open:
            messagebox.showwarning("警告", "请先打开串口")
            return

        # 确认开始升级
        if not messagebox.askyesno("确认", "确定要开始升级吗？升级过程中请勿断开连接！"):
            return

        # 初始化升级状态
        self.upgrade_in_progress = True
        self.upgrade_success = False
        self.current_packet = 0
        self.total_packets = (len(self.firmware_data) + self.packet_size - 1) // self.packet_size
        self.progress_var.set(0)

        # 更新UI状态
        self.upgrade_btn.config(state=DISABLED)
        self.cancel_btn.config(state=NORMAL)
        self.md5_check_btn.config(state=DISABLED)
        self.port_combobox.config(state=DISABLED)
        self.baud_combobox.config(state=DISABLED)
        self.connect_btn.config(state=DISABLED)

        # 启动升级线程
        threading.Thread(target=self.upgrade_process, daemon=True).start()

    def construct_command(self, type, data):
        length = len(data) + 2
        type_q_bytes = int(type).to_bytes(4, byteorder='big')
        length_q_bytes = int(length).to_bytes(4, byteorder='big')
        crc_data = type_q_bytes + length_q_bytes + data
        crc16_modbus = crcmod.predefined.Crc('modbus')
        crc16_modbus.update(crc_data)
        crc16 = int(crc16_modbus.crcValue)
        # T+L+DATA+CRC16
        return b"".join([type_q_bytes, length_q_bytes, data, bytes.fromhex(f"{crc16:04X}")])

    def upgrade_process(self):
        """升级流程的线程函数"""
        try:
            # 1. 发送AT命令进入升级模式
            self.msg_queue.put("发送命令，请求进入升级模式...")
            update_command = self.construct_command(0x0000000D, b'')
            print(update_command)
            if not self.send_command(update_command):
                raise Exception("发送升级命令失败")

            self.receive_queue.empty()
            # 等待设备进入升级模式（最多等待5秒）
            success = False
            for _ in range(10):
                time.sleep(0.5)
                receive_data = self.receive_queue.get(timeout=0.5)
                if self.check_upgrade_mode() or receive_data:
                    success = True
                    break
            self.receive_queue.task_done()

            if not success:
                raise Exception("设备未进入升级模式")
            # 2. 发送固件信息
            firmware_size = len(self.firmware_data)
            self.sent_info()
            # self.msg_queue.put(f"发送固件信息，大小: {firmware_size} 字节, 分包数: {self.total_packets}")
            # self.send_command(f"AT+FWINFO={firmware_size},{self.total_packets},{self.packet_size}")
            # ToDo 检验数据接收完成
            time.sleep(0.5)

            # 3. 分包发送固件
            self.msg_queue.put("开始发送固件数据...")

            self.current_packet = 0
            for i in range(self.total_packets):
                if not self.upgrade_in_progress:  # 检查是否取消升级
                    raise Exception("升级已取消")

                # 计算当前包的起始和结束位置
                start = i * self.packet_size
                end = start + self.packet_size
                packet_data = self.firmware_data[start:end]
                current_block_size = len(packet_data)
                # 发送包信息
                # 发送包数据（二进制）
                if self.serial_port and self.serial_port.is_open:
                    # 发送固件
                    self.firmware_data_transfer(
                        block_size=int(self.packet_size).to_bytes(4, byteorder="big"),
                        total_blocks=int(self.total_packets).to_bytes(4, byteorder="big"),
                        current_block=int(self.current_packet).to_bytes(4, byteorder="big"),
                        current_block_size=int(current_block_size).to_bytes(4, byteorder="big"),
                        firmware_data=packet_data
                    )
                    self.msg_queue.put(f"已发送 {self.current_packet}/{self.total_packets - 1} 包")
                    print(self.current_packet)
                    time.sleep(0.5)
                    self.current_packet = i + 1
                    progress = (self.current_packet / self.total_packets) * 100
                    self.progress_var.set(progress)
                # ToDo 等待设备确认 需要等待设备回复
                time.sleep(0.01)

            # 4. 发送升级完成命令
            time.sleep(1)
            self.sent_reset()
            # self.send_command("AT+UPGRADE_DONE")
            # self.msg_queue.put("固件发送完成，等待设备升级...")

            # 等待设备升级完成（最多等待30秒）
            # success = False
            # for _ in range(60):
            #     time.sleep(0.5)
            #     if self.check_upgrade_complete():
            #         success = True
            #         break
            #
            # if not success:
            #     raise Exception("设备升级超时")

            # # 5. 检查固件版本
            # self.msg_queue.put("升级完成，检查固件版本...")
            # self.send_command("AT+VERSION")
            #
            # # 等待版本信息（最多等待10秒）
            # version_success = False
            # for _ in range(20):
            #     time.sleep(0.5)
            #     # 这里可以添加检查版本是否正确的逻辑
            #     version_success = True  # 简化处理，实际应根据设备返回判断
            #     break
            #
            # if not version_success:
            #     raise Exception("无法获取设备版本信息")

            self.upgrade_success = True
            self.msg_queue.put("固件升级成功，版本验证通过！")
            # messagebox.showinfo("成功", "固件升级成功，版本验证通过！")

        except Exception as e:
            self.msg_queue.put(f"升级失败: {str(e)}")
            messagebox.showerror("失败", f"升级失败: {str(e)}")
        finally:
            # 恢复UI状态
            self.upgrade_in_progress = False
            self.after(0, self.reset_upgrade_ui)

    def check_upgrade_mode(self):
        """检查设备是否已进入升级模式"""
        # 实际应用中应根据设备返回的特定响应判断
        # 这里简化处理，假设发送命令后短时间内会进入升级模式
        return True

    def check_upgrade_complete(self):
        """检查设备是否已完成升级"""
        # 实际应用中应根据设备返回的特定响应判断
        # 这里简化处理，假设经过一定时间后完成升级
        return True

    def cancel_upgrade(self):
        """取消升级过程"""
        if messagebox.askyesno("确认", "确定要取消升级吗？这可能导致设备无法正常工作！"):
            self.upgrade_in_progress = False
            self.msg_queue.put("正在取消升级...")

    def reset_upgrade_ui(self):
        """重置升级相关的UI元素状态"""
        self.upgrade_btn.config(state=NORMAL if self.is_connected and self.firmware_path else DISABLED)
        self.cancel_btn.config(state=DISABLED)
        self.md5_check_btn.config(state=NORMAL if self.firmware_path else DISABLED)
        self.port_combobox.config(state="readonly")
        self.baud_combobox.config(state="readonly")
        self.connect_btn.config(state=NORMAL)

    def on_close(self):
        """窗口关闭时的处理"""
        self.running = False
        self.close_port()
        self.destroy()

    def create_widgets(self):
        pass
